package post

import (
	"context"
	"strconv"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/types/forum"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type UpdatePostLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdatePostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdatePostLogic {
	return &UpdatePostLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// ##25.04.01## 历史遗留文件，暂不处理
func (l *UpdatePostLogic) UpdatePost(in *forum.PostInfo) (*forum.BaseResp, error) {
	if in.Id == nil || *in.Id == 0 {
		return nil, resultx.StatusError(resultx.FORUM_POST_ID_REQUIRED, "")
	}

	if in.Author == nil || in.Author.Id == nil || *in.Author.Id == 0 {
		return nil, resultx.StatusError(resultx.FORUM_POST_AUTHOR_ID_INVALID, "")
	}

	post, err := l.svcCtx.Post.FindOneNoCache(l.ctx, nil, *in.Id)
	if err != nil {
		return nil, err
	}

	if post.PostAuthorID != *in.Author.Id {
		return nil, resultx.StatusError(resultx.FORUM_POST_AUTHOR_ID_INVALID, "")
	}

	if post.PostStatus == uint8(globalkey.StatusDeleted) || post.PostStatus == uint8(globalkey.StatusApproved) {
		return nil, resultx.StatusError(resultx.FORUM_POST_STATUS_INVALID, "")
	}

	pid := post.PostID
	now := time.Now() // 本地时间
	gmtNow := modelx.GetGmtTime(now)
	if in.ContentHtml != nil && len(strings.TrimSpace(*in.ContentHtml)) > 0 {
		post.PostContent = strings.TrimSpace(*in.ContentHtml)
	}
	post.PostModifiedDate = now
	post.PostModifiedGMT = gmtNow
	post.PostStatus = uint8(globalkey.StatusPending)

	if in.AverageRating != nil && len(*in.AverageRating) > 0 {
		post.AverageRating = *in.AverageRating
	}
	if in.CommentStatus != nil {
		if *in.CommentStatus > 0 {
			post.CommentStatus = 1
		} else {
			post.CommentStatus = 0
		}
	}

	if in.Author.Name != nil {
		post.PostAuthorNickname = *in.Author.Name
	}
	if in.Author.Email != nil {
		post.PostAuthorEmail = *in.Author.Email
	}
	if in.Author.Avatar != nil {
		post.PostAuthorAvatar = *in.Author.Avatar
	}
	if in.Author.Level != nil {
		post.PostAuthorRankID = uint8(*in.Author.Level)
	}
	if in.Author.Anonymous != nil {
		post.PostAuthorAnonymous = uint8(*in.Author.Anonymous)
	}

	rel := &model.ForumPostRel{}
	if len(in.Meta) > 0 {
		metaFilterMap := make(map[string]map[string][]any)
		metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
			"equalTo": {pid},
		}
		metaList, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
		if err != nil && err != model.ErrNotFound {
			return nil, err
		}

		metaMap := make(map[uint64]*model.ForumPostMetum) // 当前 meta 的 map
		privateMetaKeyMap := make(map[string]uint64)      // private meta 的 map(根据key寻找mid)
		privateMetaValueMap := make(map[string]uint64)    // 特殊 meta 的 map(根据val寻找mid，此val为下一级的key)
		if len(metaList) > 0 {                            // 原有的 Meta（决定现有的是增还是改）
			for _, v := range metaList {
				if len(v.MetaKey) > 0 && v.MetaValue.Valid {
					metaMap[v.MetaID] = v
					key := v.MetaKey
					val := v.MetaValue.String
					if strings.Contains(",_sticky,", ","+key+",") {
						privateMetaKeyMap[key] = v.MetaID
					}
					if strings.Contains(",_note,_grade,", ","+key+",") {
						privateMetaValueMap[val] = v.MetaID
						// e.g. 气味ID => mid
					}
				}
			}
		}

		metaValueMap := make(map[string]string)
		for _, v := range in.Meta {
			if v.Key == nil || v.Value == nil || len(strings.TrimSpace(*v.Key)) == 0 || len(strings.TrimSpace(*v.Value)) == 0 {
				continue
			}

			if v.Id != nil && *v.Id == 0 { // 特殊meta
				key := strings.TrimSpace(*v.Key)
				val := strings.TrimSpace(*v.Value)

				if mid, ok := privateMetaValueMap[val]; ok { // 特殊meta 存在 旧值
					delete(metaMap, mid) // 不要删除这个特殊meta
				} else {
					metaValueMap[val] = key // 特殊meta 由下级添加，这里先记录
					// e.g. 气味ID => "_note"
				}
			}
		}

		for _, v := range in.Meta {
			if v.Key == nil || v.Value == nil || len(strings.TrimSpace(*v.Key)) == 0 || len(strings.TrimSpace(*v.Value)) == 0 {
				continue
			}

			if v.Id != nil && *v.Id == 0 { // 特殊meta 由下级添加，先跳过
				continue
			}

			key := strings.TrimSpace(*v.Key)
			val := strings.TrimSpace(*v.Value)

			if v.Id != nil && *v.Id > 0 {
				mid := *v.Id
				if m, ok := metaMap[mid]; ok {
					delete(metaMap, mid) // 排除掉不需要删除的项

					if pk, ok := metaValueMap[key]; ok {
						rel.Meta = append(rel.Meta, &model.ForumPostMetum{ // 新增特殊meta项
							MetaKey:   pk,
							MetaValue: null.StringFrom(key),
						})
					}

					if key == m.MetaKey && val == m.MetaValue.String { // 不变，跳过
						continue
					}

					rel.Meta = append(rel.Meta, &model.ForumPostMetum{ // 修改
						MetaID:    mid,
						MetaKey:   key,
						MetaValue: null.StringFrom(val),
					})
				}
			} else {
				rel.Meta = append(rel.Meta, &model.ForumPostMetum{
					MetaKey:   key,
					MetaValue: null.StringFrom(val),
				})

				if pk, ok := metaValueMap[key]; ok {
					rel.Meta = append(rel.Meta, &model.ForumPostMetum{ // 新增特殊meta项
						MetaKey:   pk,
						MetaValue: null.StringFrom(key),
					})
				}
			}
		}

		for _, mid := range privateMetaKeyMap {
			delete(metaMap, mid)
		}
		for k, _ := range metaMap {
			rel.DelMetaIds = append(rel.DelMetaIds, k)
		}
	}

	if len(in.NewMedia) > 0 {
		mediaFilterMap := make(map[string]map[string][]any)
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
			"equalTo": {pid},
		}
		mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
			"equalTo": {globalkey.AttachmentLogTypeForumPost},
		}
		mediaList, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{}, -1, mediaFilterMap)
		if err != nil && err != model.ErrNotFound {
			return nil, err
		}

		mediaMap := make(map[uint64]*model.ForumAttachmentRelationship)
		mediaIdMap := make(map[uint64]*model.ForumAttachmentRelationship)
		if len(mediaList) > 0 { // 原有的 Meta（决定现有的是增还是改）
			for _, v := range mediaList {
				mediaMap[v.AttachmentID] = v
				mediaIdMap[v.AttachmentRelationshipID] = v
			}
		}

		for _, v := range in.NewMedia {
			var url string
			if v.Url != nil && len(*v.Url) > 0 { // 最终网址
				url = *v.Url
			}
			if len(url) == 0 && v.Uri != nil && len(*v.Uri) > 0 { // 临时网址
				url = *v.Uri
			}
			if len(url) == 0 {
				continue
			}

			var media model.ForumAttachmentRelationship
			if v.Uid != nil && *v.Uid > 0 {
				media.AttachmentRelationshipID = *v.Uid
			}
			if v.Id != nil && len(*v.Id) > 0 {
				if i, err := strconv.ParseInt(*v.Id, 10, 64); err == nil && i > 0 {
					media.AttachmentID = uint64(i)
				}
			}

			if media.AttachmentRelationshipID > 0 {
				if m, ok := mediaIdMap[media.AttachmentRelationshipID]; ok { // 已存在，修改
					delete(mediaIdMap, m.AttachmentRelationshipID) // 排除掉不需要删除的项
					if v.Uri != nil && len(*v.Uri) > 0 {
						m.AttachmentSource = *v.Uri
					}
					m.AttachmentImageURL = url
					if v.Thumbnail != nil && *v.Thumbnail > 0 {
						m.AttachmentThumbnail = uint8(*v.Thumbnail)
					}
					if v.AltText != nil && len(*v.AltText) > 0 {
						m.AttachmentImageAlt = *v.AltText
					}
					if v.Meta != nil && len(*v.Meta) > 0 {
						m.AttachmentImageMeta = *v.Meta
					}
					if v.Order != nil && *v.Order > 0 {
						m.AttachmentOrder = uint(*v.Order)
					}
					rel.Media = append(rel.Media, m)
					continue
				}
			}

			if media.AttachmentID > 0 {
				if m, ok := mediaMap[media.AttachmentID]; ok { // 已存在，修改
					delete(mediaIdMap, m.AttachmentRelationshipID) // 排除掉不需要删除的项
					if v.Uri != nil && len(*v.Uri) > 0 {
						m.AttachmentSource = *v.Uri
					}
					m.AttachmentImageURL = url
					if v.Thumbnail != nil && *v.Thumbnail > 0 {
						m.AttachmentThumbnail = uint8(*v.Thumbnail)
					}
					if v.AltText != nil && len(*v.AltText) > 0 {
						m.AttachmentImageAlt = *v.AltText
					}
					if v.Meta != nil && len(*v.Meta) > 0 {
						m.AttachmentImageMeta = *v.Meta
					}
					if v.Order != nil && *v.Order > 0 {
						m.AttachmentOrder = uint(*v.Order)
					}
					rel.Media = append(rel.Media, m)
					continue
				}
			}

			if v.Uri != nil && len(*v.Uri) > 0 {
				media.AttachmentSource = *v.Uri
			}
			media.AttachmentImageURL = url
			if v.Thumbnail != nil && *v.Thumbnail > 0 {
				media.AttachmentThumbnail = uint8(*v.Thumbnail)
			}
			if v.AltText != nil && len(*v.AltText) > 0 {
				media.AttachmentImageAlt = *v.AltText
			}
			if v.Meta != nil && len(*v.Meta) > 0 {
				media.AttachmentImageMeta = *v.Meta
			}
			if v.Order != nil && *v.Order > 0 {
				media.AttachmentOrder = uint(*v.Order)
			}
			rel.Media = append(rel.Media, &media)
		}

		for _, v := range mediaIdMap {
			rel.DelMediaIds = append(rel.DelMediaIds, v.AttachmentRelationshipID)
		}
	}

	post.PhotoCount = uint(len(rel.Media))

	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, resultx.StatusError(resultx.DB_ERROR, "")
	}

	err = l.svcCtx.Post.Update(l.ctx, tx, post, rel)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	tx.Commit()

	return &forum.BaseResp{}, nil
}
